/*read.cpp
 *This program reads specified block on created RAID and saves it to specified file.
 *Created on: 2013.12.24
 *Author: Petrunin D.S.
 */
#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include "base.h"

int readRAID0(FILE* file, int blockN, int nDisks, int nBlocks, int blockS) {
	if (mapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	int offset = (blockN - 1) * blockS;
	for (int i = 1; i <= nDisks; i++)
		fputs(mappedDataArray[i] + offset, file);
	fclose(file);
	if (unmapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	return 0;
}

int readRAID1(FILE* file, int blockN, int nDisks, int nBlocks,	int blockS) {
	if (mapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	int offset = (blockN - 1) * blockS;
	fputs(mappedDataArray[1] + offset, file);//read mappedData
	fclose(file);
	if (unmapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	return 0;
}

int readRAID3(FILE* file, int blockN, int nDisks, int nBlocks,	int blockS) {
	if (mapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	int offset = (blockN - 1) * blockS;
	for (int k = 0; k < blockS; k++) {
		for (int i = 1; i < nDisks; i++) {
			if (*(mappedDataArray[i] + offset + k) != '\0')
				fputc(*(mappedDataArray[i] + offset + k), file);
		}
	}
	fclose(file);
	if (unmapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	return 0;
}


int readRAID4(FILE* file, int blockN, int nDisks, int nBlocks,	int blockS) {
	if (mapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	int offset = (blockN - 1) * blockS;
	for (int i = 1; i < nDisks; i++)
		fputs(mappedDataArray[i] + offset, file);
	fclose(file);
	if (unmapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	return 0;
}


int readRAID5(FILE* file, int blockN, int nDisks, int nBlocks,	int blockS) {
	if (mapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	int offset = (blockN - 1) * blockS;
	int parityDisk = nDisks - (blockN - 1);
	for (int i = 1; i <= nDisks; i++) {
		if (parityDisk != i)
			fputs(mappedDataArray[i] + offset, file);
	}
	fclose(file);
	if (unmapping(nDisks, nBlocks, blockS, false) == 1)
		return 1;
	return 0;
}


int main(int argc, char* argv[]) {
	if (argc < 3) {
		cout << "Not enough parameters\n";
		return 1;
	}
	FILE* config = fopen("config", "r");
	if (config == NULL) {
		cout << "Can't open config file.\n";
		return 1;
	}
	int nDisks, nBlocks, blockS, RAIDLevel;
	fscanf(config, "%i\n%i\n%i\n%i\n", &nDisks, &nBlocks, &blockS,	&RAIDLevel);
	fclose(config);
	if (failedDisk(nDisks, false)) {
		cout << "Rebuild RAID.\n";
		return 1;
	}

	int blockN = atoi(argv[1]);
	if ((blockN == 0) || (blockN > nBlocks)) {
		cout << "Number of blocks must be 1.." << nBlocks << "\n";
		return 1;
	}

	char* fileName = argv[2];
	FILE * file;
	file = fopen(fileName, "wb+");
	if (file == NULL) {
		cout << "Can't create or open file " << file << "\n";
		return 1;
	}

	switch (RAIDLevel) {
	case 0:
		return readRAID0(file, blockN, nDisks, nBlocks,
				blockS);
	case 1:
		return readRAID1(file, blockN, nDisks, nBlocks,
				blockS);
	case 3:
		return readRAID3(file, blockN, nDisks, nBlocks,
				blockS);
	case 4:
		return readRAID4(file, blockN, nDisks, nBlocks,
				blockS);
	case 5:
		return readRAID5(file, blockN, nDisks, nBlocks,
				blockS);
	}
}

